#include "horizontal_data.h"

#include <time.h>
#include <stdio.h>
#include <stdlib.h>

#include "pfunc.h"
#include "Log.h"

float  HorizontalData::FLIMIT = float(0.0000001);

HorizontalData::HorizontalData(/* args */)
{
}

HorizontalData::~HorizontalData()
{
}

void HorizontalData::getAdditionalInfo(unsigned long long _devID, unsigned int _pID
	, std::string &devDesc, std::string &pDesc, pyfree::EventWay &eway_)
{
	std::map<unsigned long long, pyfree::Dev>::iterator it = devs.find(_devID);
	if (it != devs.end())
	{
		devDesc = it->second.devInfo.desc;
		std::map<unsigned int, pyfree::PInfo>::iterator itp = it->second.pInfo.find(_pID);
		if (itp != it->second.pInfo.end())
		{
			pDesc = itp->second.desc;
			eway_ = itp->second.eway;
		}
	}
};

//查找值
bool HorizontalData::getValue(unsigned long long _devID, unsigned int _pID, float &_val)
{
	bool ret = false;
	
	std::map<unsigned long long, pyfree::Dev>::iterator it = devs.find(_devID);
	if (it != devs.end())
	{
		std::map<unsigned int, PInfo>::iterator itp = it->second.pInfo.find(_pID);
		if (itp != it->second.pInfo.end()) 
		{
			devs_point_mutex.Lock();
			_val = itp->second.defVal;
			devs_point_mutex.Unlock();
			ret = true;
		}
	}
	return ret;
}

//计算值
bool HorizontalData::getCValue(unsigned long long _devID, unsigned int _pID, float &_val)
{
	bool ret = false;
	
	std::map<unsigned long long, Dev>::iterator it = devs.find(_devID);
	if (it != devs.end())
	{
		std::map<unsigned int, pyfree::PInfo>::iterator itp = it->second.pInfo.find(_pID);
		if (itp != it->second.pInfo.end()) 
		{
			if (abs(itp->second.ratio) < FLIMIT)
			{
				_val = _val - itp->second.base;
			}
			else
			{
				_val = (_val - itp->second.base) / itp->second.ratio;
			}
			ret = true;
		}
	}
	
	return ret;
}

inline bool HorizontalData::compareVal(float _fv, float _tv, pyfree::CompareType _ct)
{
	bool ret = false;
	switch (_ct)
	{
	case OnEqual:
		ret = (abs(_fv - _tv) < FLIMIT);
		break;
	case OnMore:
		ret = (_fv > _tv);
		break;
	case OnLess:
		ret = (_fv < _tv);
		break;
	case ComTDef:
		break;
	default:
		break;
	}
	return ret;
}

//遥测跳变计算
inline bool HorizontalData::comBreak(float _oldval, float _newval, float combase, float rate)
{
	bool ret = false;
	if (abs(combase) > 0
		&& ((abs(_newval - _oldval) / abs(combase)) > 0.01*rate))
	{
		ret = true;
	}
	return ret;
};

int HorizontalData::getCurTVMin(int &day_)
{
	time_t _t = time(NULL);
	int min_ = 0;
	struct tm _tt;
#ifdef WIN32
	localtime_s(&_tt, &_t);
#else
	localtime_r(&_t, &_tt);
#endif
	day_ = _tt.tm_mday;
	min_ = 60 * _tt.tm_hour + _tt.tm_min;
	return min_;
};
//curMin  startMin  endMin,[0,1440]
bool HorizontalData::isMapTVMin(int curMin, int startMin, int endMin)
{
	bool ret = false;
	if (startMin <= endMin) 
	{
		if (curMin >= startMin&&curMin < endMin)
			ret = true;
	}
	else 
	{
		if (curMin >= startMin||curMin < endMin)
			ret = true;
	}
	return ret;
};

//条件判定与标记
bool HorizontalData::getConditionJude(unsigned long long _devID, unsigned int _pID, float rVal
	, bool &_valMap, bool &_valChange, bool planf, pyfree::CompareType comf)
{
	bool ret = false;
	
	std::map<unsigned long long, pyfree::Dev>::iterator it = devs.find(_devID);
	if (it != devs.end())
	{
		std::map<unsigned int, pyfree::PInfo>::iterator itp = it->second.pInfo.find(_pID);
		if (itp != it->second.pInfo.end()) 
		{
			devs_point_mutex.Lock();
			_valMap = compareVal(itp->second.defVal, rVal, comf);
			if (planf) 
			{
				_valChange = itp->second.ValChange;
				//辅助条件监测,数据变化判定
				if (itp->second.ValChange&&_valMap)
				{
					itp->second.ValChange = false;
				}
			}
			else
			{
				_valChange = itp->second.ValChangeCopy;
				//辅助条件监测,数据变化判定
				if (itp->second.ValChangeCopy&&_valMap)
				{
					itp->second.ValChangeCopy = false;
				}
			}
			devs_point_mutex.Unlock();
			ret = true;
		}
	}

	return ret;
};

bool HorizontalData::getDevIDs(std::vector<long> &_list)
{
	try {
		for (std::map<unsigned long long, pyfree::Dev>::iterator it = devs.begin(); it != devs.end(); ++it)
		{
			_list.push_back(static_cast<long>(it->second.devInfo.devID));
		}
	}
	catch (...) {
		Print_WARN("error for getDevIDs,please check your config!\n");
	}
	return !_list.empty();
}

bool HorizontalData::getDevs(std::vector<pyfree::Dev> &devs_, bool filter)
{
	for (std::map<unsigned long long, pyfree::Dev>::iterator it = devs.begin(); it != devs.end(); ++it)
	{
		if (filter) {
			devs_point_mutex.Lock();
			Dev dev_ = it->second;
			devs_point_mutex.Unlock();
			std::map<unsigned int, pyfree::PInfo>::iterator itp = dev_.pInfo.begin();
			while (itp!=dev_.pInfo.end())
			{
				if (itp->second.clientOrder <= 0)
				{
					#ifdef WIN32
					itp = dev_.pInfo.erase(itp);
					#else
					std::map<unsigned int, pyfree::PInfo>::iterator ittmp=itp++;
				    dev_.pInfo.erase(ittmp);
					#endif
				}
				else {
					itp++;
				}
			}
			devs_.push_back(dev_);
		}
		else {
			devs_point_mutex.Lock();
			devs_.push_back(it->second);
			devs_point_mutex.Unlock();
		}
	}

	return !devs_.empty();
}

bool HorizontalData::getDevTriples(std::map<unsigned long long, pyfree::AliyunDevices> &deviceTriples)
{
	for (std::map<unsigned long long, pyfree::Dev>::iterator it = devs.begin(); it != devs.end(); ++it)
	{
		if(it->second.devInfo.device_triples.invalid())
			continue;
		pyfree::AliyunDevices adevices;
		adevices.atriples = it->second.devInfo.device_triples;
		//adevices.upFlag = false;
		for (std::map<unsigned int, pyfree::PInfo>::iterator itp = it->second.pInfo.begin(); 
			itp != it->second.pInfo.end(); ++itp) 
		{
			if (!itp->second.aliyun_key.empty())
			{
				adevices.aliyun_keys[itp->first] = itp->second.aliyun_key;
			}
		}
		//
		for (std::map<std::string, std::string>::iterator itTag = it->second.devInfo.dev_tags.begin();
			itTag!=it->second.devInfo.dev_tags.end(); ++itTag)
		{
			adevices.dev_tags[itTag->first] = itTag->second;
		}
		deviceTriples[it->first] = adevices;
	}
	return !deviceTriples.empty();
}

bool HorizontalData::setHValue(unsigned long long _devID, unsigned int _pID, PValueRet &pret, bool isVirtualId)
{
	bool ret			= false;//返回值
	bool valChange		= false;//是否发生值改变或刷新
	bool valChange_ali	= false;//上送阿里云的数据是否发生值改变或刷新
	bool changRecordF	= false;//是否记录
	bool clientOrder	= false;//客户端是否订购
	//
	pyfree::PType ptype_ = pyfree::PTDef;

	std::map<unsigned long long, pyfree::Dev>::iterator it = devs.find(_devID);
	if (it != devs.end())
	{
		std::map<unsigned int, pyfree::PInfo>::iterator itp = it->second.pInfo.find(_pID);
		if (itp != it->second.pInfo.end()) 
		{
			ptype_ = itp->second.pType;
			if (pyfree::OnYX == itp->second.pType || pyfree::OnYXS == itp->second.pType)
			{
				pret.val_actual = static_cast<float>(pret.val_actual ? 1 : 0);
			}
			else {
				pret.val_actual = pret.val_actual*(itp->second.ratio) + itp->second.base;
			}
			bool ValChange_this = false;	//本次真实变化
			pret.val_old		= itp->second.defVal;
			pret.devDesc		= it->second.devInfo.desc;
			pret.pDesc			= itp->second.desc;
			pret.eway_			= itp->second.eway;
			//
			devs_point_mutex.Lock();
			itp->second.valUpdateClock = pyfree::getClockTime();
			if (abs(itp->second.defVal - pret.val_actual)>FLIMIT)
			{
				itp->second.ValChangeCopy = itp->second.ValChange = ValChange_this = valChange  = true;
				valChange_ali = itp->second.aliyun_key.empty()?false:true;
				pret.val_old_clock		= itp->second.valTimeClock;
				itp->second.valTimeClock = itp->second.valUpdateClock;
				itp->second.markT		= static_cast<unsigned int>(time(NULL)) + itp->second.upLoopTime;
				itp->second.markT_ali	= static_cast<unsigned int>(time(NULL)) + itp->second.upLoopTime_ali;
			}
			if (itp->second.markT < static_cast<unsigned int>(time(NULL)))//刷新时变化
			{
				valChange = true;
				itp->second.markT = static_cast<unsigned int>(time(NULL)) + itp->second.upLoopTime;
			}
			if (itp->second.markT_ali < static_cast<unsigned int>(time(NULL)))//刷新时变化
			{
				valChange_ali = itp->second.aliyun_key.empty()?false:true;
				itp->second.markT_ali = static_cast<unsigned int>(time(NULL)) + itp->second.upLoopTime_ali;
			}
			itp->second.defVal	= pret.val_actual;
			devs_point_mutex.Unlock();
			//数值变更,并落在告警时间区域
			//追加不刷新事件每天发送次数重置
			//长期不刷新和不变更移到巡检线程处置
			if (ValChange_this) {
				int day_ = 0;
				int min_ = getCurTVMin(day_);
				bool minMap_ = isMapTVMin(min_, itp->second.evtStartTime, itp->second.evtEndTime);
				if (minMap_) {
					if (pyfree::OnYC == itp->second.pType || pyfree::OnYCS == itp->second.pType)
					{
						if (compareVal(pret.val_actual, itp->second.valLimitUp,pyfree::OnMore))
						{
							pret.evts.push_back(pyfree::YCUpOverLimit);//遥测越上限
							pret.waringflag = true;
							pret.val_limitUp = itp->second.valLimitUp;
						}
						if (compareVal( pret.val_actual, itp->second.valLimitDown,pyfree::OnLess))
						{
							pret.evts.push_back(pyfree::YCDownOverLimit);//遥测越下限
							pret.waringflag = true;
							pret.val_limitDown = itp->second.valLimitDown;
						}
						if (pret.val_old_clock > 100
							&& comBreak(pret.val_old, itp->second.defVal, itp->second.comValLimit, itp->second.comRate))
						{
							pret.evts.push_back(pyfree::YCBreak);//遥测跳变
							pret.waringflag = true;
							pret.val_base = itp->second.comValLimit;
							pret.val_rate = itp->second.comRate;
						}
						//>100预防初次刷新数据出现告警
						if (pret.val_old_clock > 100
							&& (itp->second.valTimeClock - pret.val_old_clock) < itp->second.shakeTimeInterval)
						{
							//printf("YCDisturb（%lld,%lld)\n", itp->second.valTimeClock, pret.val_old_clock);
							pret.evts.push_back(pyfree::YCDisturb);//遥测扰动
							pret.waringflag = true;
							pret.shake_interval = itp->second.shakeTimeInterval;
						}
					}
					else if (pyfree::OnYX == itp->second.pType || pyfree::OnYXS == itp->second.pType)
					{
						if (pret.val_old_clock > 100
							&& (itp->second.valTimeClock - pret.val_old_clock) < itp->second.shakeTimeInterval)
						{
							//printf("YXShake（%lld,%lld)\n", itp->second.valTimeClock, pret.val_old_clock);
							pret.evts.push_back(pyfree::YXShake);//遥信扰动
							pret.waringflag = true;
							pret.shake_interval = itp->second.shakeTimeInterval;
						}
					}
					else
					{
						;
					}
				}
			}
			changRecordF	= itp->second.changeRecord;
			clientOrder		= (itp->second.clientOrder>0?true:false);
			ret = true;
		}
	}
	
	pret.sendflag		= (valChange && clientOrder) ? true : false;
	pret.sendflag_ali	= (valChange_ali && clientOrder) ? true : false;
	pret.recordflag		= (changRecordF && valChange) ? true : false;
	//虚拟点设置时及时上送，主要是由上层应用对虚拟点设值引起
	if ((pret.sendflag|| pret.sendflag_ali)&&isVirtualId)
	{
		unsigned int _usec = pyfree::getUsec();
		DataToThird _wdlc(_devID, _pID, ptype_
			, static_cast<unsigned int>(time(NULL))
			, _usec, pret.val_actual);
		if (pret.sendflag)
		{
			send_data_to_third(_wdlc);
		}
		//虚拟点设置时及时上送阿里云,其轮询间隔时间较长,节省流量,为了省钱
		if (pret.sendflag_ali) 
		{
			send_data_to_third(_wdlc, true);
		}
	}
	return ret;
}

void HorizontalData::TimeUpVirtual()
{
	unsigned int _usec = pyfree::getUsec();
	unsigned int _sec = static_cast<unsigned int>(time(NULL));
	std::queue<DataToThird> _wdlcs;
	std::queue<DataToThird> _wdlcs_ali;

	for (std::map<unsigned long long, pyfree::Dev>::iterator it = devs.begin(); it != devs.end(); ++it)
	{
		for (std::map<unsigned int, pyfree::PInfo>::iterator itp = it->second.pInfo.begin(); itp != it->second.pInfo.end(); ++itp)
		{
			DataToThird _wdlc(static_cast<unsigned long long>(it->second.devInfo.devID), itp->second.pID, itp->second.pType
				, _sec, _usec, itp->second.defVal);
			devs_point_mutex.Lock();
			if (itp->second.clientOrder
				&& (3 == itp->second.pType || 4 == itp->second.pType))
			{
				if ((itp->second.markT + itp->second.upLoopTime) < _sec)
				{
					itp->second.markT = _sec;
					_wdlcs.push(_wdlc);
				}
				if ((itp->second.markT_ali + itp->second.upLoopTime_ali) < _sec)
				{
					itp->second.markT_ali = _sec;
					if(!itp->second.aliyun_key.empty())
						_wdlcs_ali.push(_wdlc);
				}
			}
			devs_point_mutex.Unlock();
		}
	}
	
	while (!_wdlcs.empty())
	{
		DataToThird _wdlc = _wdlcs.front();
		send_data_to_third(_wdlc);
		_wdlcs.pop();
	}
	while (!_wdlcs_ali.empty())
	{
		DataToThird _wdlc = _wdlcs_ali.front();
		send_data_to_third(_wdlc, true);
		_wdlcs_ali.pop();
	}
}


//将长期无变化和长期不刷新的判定移到独立线程处理，不占用数据接收处理逻辑时间
void HorizontalData::TimeCheck()
{
	//追加不刷新事件每天发送次数重置
	int day_ = 0;
	int min_ = getCurTVMin(day_);
	unsigned long long  cur_clock_t = pyfree::getClockTime();
	for (std::map<unsigned long long, pyfree::Dev>::iterator it = devs.begin(); it != devs.end(); ++it)
	{
		for (std::map<unsigned int, pyfree::PInfo>::iterator itp = it->second.pInfo.begin(); itp != it->second.pInfo.end(); ++itp)
		{
			if (itp->second.nChTInterval > 0||itp->second.nUpTInterval>0) 
			{
				bool minMap_ = isMapTVMin(min_, itp->second.evtStartTime, itp->second.evtEndTime);//是否满足告警时间区域
				if (!minMap_)
				{
					continue;
				}
				//日期变更时重置次数
				devs_point_mutex.Lock();
				if (itp->second.evtForDay != day_)
				{
					itp->second.evtForDay = day_;
					itp->second.evtNoChangeSendCountForDay = 0;
					itp->second.evtNoUpdateSendCountForDay = 0;
				}
				devs_point_mutex.Unlock();
				bool evt_flag = false;
				pyfree::EventType evt_type;
				//长期不变更判定,满足时限约束和次数约束
				if (itp->second.nChTInterval>0
					&& itp->second.evtNoChangeSendCountForDay < itp->second.evtNoChangeSendCountForLimit)
				{
					int ll_clock_t = abs(static_cast<int>(cur_clock_t - itp->second.valTimeClock));//最后一次变更时间与当前时间差
					if (ll_clock_t > 1000 * itp->second.nChTInterval)
					{
						if (OnYC == itp->second.pType || OnYCS == itp->second.pType)
						{
							//遥测长期不变更
							evt_flag = true;
							evt_type = pyfree::YCNoChange;
						}
						else if (OnYX == itp->second.pType || OnYXS == itp->second.pType) {
							//遥信长期不变更
							evt_flag = true;
							evt_type = pyfree::YXNoChange;
						}
						else {
							continue;
						}
					}
				}
				//长期不刷新判定,满足时限约束和次数约束
				if (itp->second.nUpTInterval>0 
					&& itp->second.evtNoUpdateSendCountForDay < itp->second.evtNoUpdateSendCountForLimit)
				{
					int ll_clock_t = abs(static_cast<int>(cur_clock_t - itp->second.valUpdateClock));//最后一次刷新时间与当前时间的差
					if (ll_clock_t > 1000 * itp->second.nUpTInterval)
					{
						if (pyfree::OnYC == itp->second.pType || pyfree::OnYCS == itp->second.pType)
						{
							//遥测长期不刷新
							evt_flag = true;
							evt_type = pyfree::YCNoUpdate;
						}
						else if (pyfree::OnYX == itp->second.pType || pyfree::OnYXS == itp->second.pType) {
							//遥信长期不刷新
							evt_flag = true;
							evt_type = pyfree::YXNoUpdate;
						}
						else {
							continue;
						}
					}
				}
				if (evt_flag) 
				{
					devs_point_mutex.Lock();
					switch (evt_type)
					{
					case pyfree::YXNoChange:case pyfree::YCNoChange:
						itp->second.evtNoChangeSendCountForDay += 1;
						itp->second.valTimeClock = cur_clock_t;//告警时刷新时间,防止连续告警
						break;
					case pyfree::YXNoUpdate:case pyfree::YCNoUpdate:
						itp->second.evtNoUpdateSendCountForDay += 1;
						itp->second.valUpdateClock = cur_clock_t;//告警时刷新时间,防止连续告警
						break;
					default:
						break;
					}
					devs_point_mutex.Unlock();
					//waring;
					EventForWaring event_;
					//
					event_.grade = pyfree::majorLevel;
					event_.send_ = itp->second.eway;
					event_.execTime = pyfree::getCurrentTimeByFormat("%04d%02d%02dT%02d%02d%02dZ");//短信平台要求格式
					event_.taskDesc = "DataRouting ";
					event_.devID = static_cast<unsigned long>(it->second.devInfo.devID);
					event_.devDesc = it->second.devInfo.desc;
					event_.pID = itp->second.pID;
					event_.pDesc = itp->second.desc;
					event_.type = evt_type;
					float val_ = 0.0;
					int timeLimit_ = 0;
					switch (event_.type)
					{
					case pyfree::YXNoChange:
						event_.taskID = 108808801;
						val_ = static_cast<float>(itp->second.defVal ? 1 : 0);
						timeLimit_ = itp->second.nChTInterval;
						break;
					case pyfree::YCNoChange:
						event_.taskID = 108808802;
						val_ = itp->second.defVal*(itp->second.ratio) + itp->second.base;
						timeLimit_ = itp->second.nChTInterval;
						break;
					case pyfree::YXNoUpdate:
						event_.taskID = 108808803;
						val_ = static_cast<float>(itp->second.defVal ? 1 : 0);
						timeLimit_ = itp->second.nUpTInterval;
						break;
					case pyfree::YCNoUpdate:
						event_.taskID = 108808804;
						val_ = itp->second.defVal*(itp->second.ratio) + itp->second.base;
						timeLimit_ = itp->second.nUpTInterval;
						break;
					case pyfree::DefAlarmType:
						break;
					default:
						break;
					}
					//值状况描述,阿里短信接口限定变量字段20以内
					char buf_val[64] = { 0 };
					sprintf(buf_val, "A(%.1f)", val_);
					event_.valDesc = std::string(buf_val);
					//全状况描述
					char buf_comment[512] = { 0 };
					sprintf(buf_comment
						, "DataRouting VerificationForPValue taskID(%lu),"
						"devID(%lu),devDesc(%s),pID(%lu),pDesc(%s),pType(%d)"
						",actual_value(%0.2f),TimeLimit(%d)"
						, event_.taskID
						, event_.devID, event_.devDesc.c_str()
						, event_.pID, event_.pDesc.c_str(), static_cast<int>(itp->second.pType)
						, val_, timeLimit_);
					event_.Comment = std::string(buf_comment);
                    add_event(event_);
					// queueforwar->add(event_);
				}
			}
		}
	}
}
